#ifndef _SOCKETIO_H
#define _SOCKETIO_H
#include <unistd.h>
#include "net_tool.h"
#include "DataFrame.h"
#include <stdio.h>
#include"Exception.h"

/**
 * 与在socket上写数据相关的类，封装了一系列的方法
 * 在内部自动管理帧数据的发送
 * 方法若出现错误均会抛出异常
 */
class SocketWriter {
    public:
        SocketWriter(socketinf sinf);
        socketinf si;
        bool sendFrame(unsigned char flag, unsigned long long payloadLen)
            ;

        // 发送数据（需要先发帧），会保证所有数据完整发送完毕
        void write(const char * buf, size_t len) ;

        // 快捷发送一次数据（不需要发帧，但需要确保上一次的帧的负载数据完全发送完毕）
        void writeOne(const char * buf, unsigned long long len) ;
        /**
         * 设置写超时
         */
        void setTimeout(unsigned int sec) ;
    private:
        DataFrame dataframe;
        // 剩余需要发送的负载长度
        unsigned long long surplus = 0;
};


/**
 * 与在socket上读数据相关的类，封装了一系列的方法
 * 在内部自动管理帧数据的接收和解析
 * 方法若出现错误均会抛出异常
 */
class SocketReader {
    public:
        SocketReader(socketinf si);
        ~SocketReader();
        /** 
         * 读取一个帧
         * @return Flag
         */
        int readFrame() ;

        unsigned char getFrameFlag();
        unsigned long long getFrameLength();

        /**
         * 读取二进制类型数据，成功返回读取的数量，失败抛出异常，读到帧末返回-1
         * @param buf 数据保存buffer
         * @param max_len 一次最大读取长度
         */ 
        int read(char * buf, size_t max_len) ;

        /**
         * 快捷读取（不需要读帧，但需要确保没有负载数据未完成读取），若max_len不足以容纳所有接收到的数据，将抛出异常
         */
        int readOne(char * buf, size_t max_len) ;

        /**
         * 重置内部的数据帧长度信息
         */
        void resetPayloadLen(unsigned long long len);

        /**
         * 设置读超时
         */
        void setTimeout(unsigned int sec) ;
    private:
        FILE * f_fd;
        DataFrame dataFrame;

        // 剩余所需读取的负载长度
        unsigned long long payloadLength = 0;
        socketinf si;
};

class SocketIO {
    public:
        ~SocketIO();
        SocketIO(socketinf si);
        /**
         * 构造的同时进行读写超时设置
         * @param si Socket信息类
         * @param sec 读写超时（秒）
         */
        SocketIO(socketinf si, unsigned int sec) ;
        void close();

        /**
         * 单独取出一个socket描述符  
         * 
         */
        SOCKET_T getSocketFD();
        SocketReader * socketReader;
        SocketWriter * socketWriter;
    private:
        FILE * f_fd;
        DataFrame dataFrame;

        // 剩余所需读取的负载长度
        size_t payloadLength;
        socketinf si;
};
#endif